package com.ganbo.demo.caffeine.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redis操作封装
 *
 * @author: GanBo
 * @date: 2023/3/30 13:28
 */

@Service
public class RedisService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    //===================分布式锁实现========

    /**
     * 获取锁
     *
     * @param lockKey
     * @return
     */
    public boolean tryLock(String lockKey) {
        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, String.valueOf(System.currentTimeMillis())));
    }

    /**
     * 释放锁
     *
     * @param lockKey
     * @return
     */
    public boolean removeLock(String lockKey) {
        redisTemplate.delete(lockKey);
        return true;
    }


    //===================Key（键），简单的key-value操作

    /**
     * 实现命令：TTL key，以秒为单位，返回给定 key的剩余生存时间(TTL, time to live)。
     *
     * @param key
     * @return
     */
    public long ttl(String key) {
        return stringRedisTemplate.getExpire(key);
    }

    /**
     * 实现命令：expire 设置过期时间，单位秒
     *
     * @param key
     * @return
     */
    public void expire(String key, long timeout) {
        stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令：INCR key，增加key一次
     *
     * @param key
     * @return
     */
    public long incr(String key, long delta) {
        return stringRedisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 实现命令：KEYS pattern，查找所有符合给定模式 pattern的 key
     */
    public Set<String> keys(String pattern) {
        return stringRedisTemplate.keys(pattern);
    }

    /**
     * 实现命令：DEL key，删除一个key
     *
     * @param key
     */
    public void del(String key) {
        stringRedisTemplate.delete(key);
    }

    /**
     * 实现命令：EXISTS key，检查指定key是否存在
     *
     * @param key
     * @return
     */
    public boolean exists(String key) {
        return stringRedisTemplate.hasKey(key);
    }

    //===================String（字符串）

    /**
     * 实现命令：SET key value，设置一个key-value（将字符串值 value关联到 key）
     *
     * @param key
     * @param value
     */
    public void set(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }

    /**
     * 实现命令：SET key value EX seconds，设置key-value和超时时间（秒）
     *
     * @param key
     * @param value
     * @param timeout （以秒为单位）
     */
    public void set(String key, String value, long timeout) {
        stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令：GET key，返回 key所关联的字符串值。
     *
     * @param key
     * @return value
     */
    public String get(String key) {
        return (String) stringRedisTemplate.opsForValue().get(key);
    }

    //===================Hash（哈希表）

    /**
     * 实现命令：HSET key field value，将哈希表 key中的域 field的值设为 value
     *
     * @param key
     * @param field
     * @param value
     */
    public void hset(String key, String field, Object value) {
        stringRedisTemplate.opsForHash().put(key, field, value);
    }

    /**
     * 实现命令：HGET key field，返回哈希表 key中给定域 field的值
     *
     * @param key
     * @param field
     * @return
     */
    public String hget(String key, String field) {
        return (String) stringRedisTemplate.opsForHash().get(key, field);
    }

    /**
     * 实现命令：HDEL key field [field ...]，删除哈希表 key 中的一个或多个指定域，不存在的域将被忽略。
     *
     * @param key
     * @param fields
     */
    public void hdel(String key, Object... fields) {
        stringRedisTemplate.opsForHash().delete(key, fields);
    }

    /**
     * 实现命令：HGETALL key，返回哈希表 key中，所有的域和值。
     *
     * @param key
     * @return
     */
    public Map<Object, Object> hgetall(String key) {
        return stringRedisTemplate.opsForHash().entries(key);
    }

    //===================List（列表）

    /**
     * 实现命令：LPUSH key value，将一个值 value插入到列表 key的表头
     *
     * @param key
     * @param value
     * @return 执行 LPUSH命令后，列表的长度。
     */
    public long lpush(String key, String value) {
        return stringRedisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 实现命令：LPOP key，移除并返回列表 key的头元素。
     *
     * @param key
     * @return 列表key的头元素。
     */
    public String lpop(String key) {
        return (String) stringRedisTemplate.opsForList().leftPop(key);
    }

    /**
     * 实现命令：RPUSH key value，将一个值 value插入到列表 key的表尾(最右边)。
     *
     * @param key
     * @param value
     * @return 执行 LPUSH命令后，列表的长度。
     */
    public long rpush(String key, String value) {
        return stringRedisTemplate.opsForList().rightPush(key, value);
    }


    //===================Sorted set（有序集合）

    /**
     * 实现命令: ZADD scores key，添加一个袁术，同时设置该元数据的分数，如果存在就覆盖并且返回false
     *
     * @param key
     * @param value
     * @param scores
     * @return
     */
    public boolean zadd(String key, String value, double scores) {
        return stringRedisTemplate.opsForZSet().add(key, value, scores);
    }

    /**
     * 从有序集合中移除一个或多个
     *
     * @param key
     * @param values
     * @return
     */
    public long remove(String key, String... values) {
        return stringRedisTemplate.opsForZSet().remove(key, values);
    }


    /**
     * 增加元素的score值，并返回增加后的值
     *
     * @param key
     * @param value
     * @param scores
     * @return
     */
    public double incrementScore(String key, String value, double scores) {
        return stringRedisTemplate.opsForZSet().incrementScore(key, value, scores);
    }

    /**
     * 返回有序集合中指定成员的排名，其中有序集合成员按分数值递增(从0开始从小到大，0表示第一名最小的)顺序排列
     *
     * @param key
     * @param value 有序集合中的指定成员
     * @return
     */
    public Long rank(String key, Object value) {
        return stringRedisTemplate.opsForZSet().rank(key, value);
    }

    /**
     * 返回有序集合中指定成员的排名，其中有序集合成员按分数值递减(从0开始从大到小，0表示第一名最大的)顺序排列
     *
     * @param key
     * @param value 有序集合中的指定成员
     * @return
     */
    public Long reversRank(String key, Object value) {
        return stringRedisTemplate.opsForZSet().reverseRank(key, value);
    }


    /**
     * 通过索引区间返回有序集合成指定区间内的成员，其中有序集成员按分数值递增(从小到大)顺序排列
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public Set<String> range(String key, long start, long end) {
        return stringRedisTemplate.opsForZSet().range(key, start, end);
    }


}

